package com.jumi.microservice.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.jumi.microservice.common.constant.RedisKeyConstant;
import com.jumi.microservice.common.exception.BusinessException;
import com.jumi.microservice.common.redis.RedisCache;
import com.jumi.microservice.common.utils.EnumUtil;
import com.jumi.microservice.common.utils.JwtUtil;
import com.jumi.microservice.config.UserTokenConfig;
import com.jumi.microservice.constant.*;
import com.jumi.microservice.domain.Account;
import com.jumi.microservice.domain.dto.UserLoginDTO;
import com.jumi.microservice.domain.dto.UserTokenDTO;
import com.jumi.microservice.mapper.AccountMapper;
import com.jumi.microservice.service.UserLoginService;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;


/**
 * 账号登录管理Service组件
 *
 * @author Administrator
 */

@Service
public class UserLoginServiceImpl implements UserLoginService {

    /**
     * 账号管理mapper组件
     */
    @Autowired
    private AccountMapper accountMapper;

    @Autowired
    UserTokenConfig userTokenConfig;

    @Autowired
    private RedisCache redisCache;

    /**
     * 用户登录
     *
     * @param userLogin 用户登录VO
     * @return 用户TokenVo
     */
    @Override
    public UserTokenDTO login(UserLoginDTO userLogin) {
        ExceptionEnum.FAIL_NULL.doThrowIf(userLogin == null);

        String userAccount = userLogin.getAccount();
        LambdaQueryWrapper<Account> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(Account::getStatus, StatusEnum.STATUS_YES.getCode());
        wrapper.eq(Account::getIsDel, StatusEnum.STATUS_NO.getCode());
        wrapper.eq(StringUtils.isNotEmpty(userAccount), Account::getUserAccount, userAccount);

        Account account = accountMapper.selectOne(wrapper);
        if (account == null) {
            throw new BusinessException(UserAccountEnum.USER_NOT_EXISTED);
        }

        LoginTypeEnum loginTypeEnum = EnumUtil.getByCode(userLogin.getLoginType(), LoginTypeEnum.class);
        if (loginTypeEnum == LoginTypeEnum.PASSWORD_LOGIN) {
            //密码登录
            boolean res = checkPassword(userLogin.getPwdOrCode(), account.getSalt(), account.getPassword());
            if (!res) {
                throw new BusinessException(UserAccountEnum.PASSWORD_ERROR);
            }
        } else {
            //验证码登录
        }
        UserTokenDTO userToken = new UserTokenDTO();
        userToken.setUid(account.getId());
        userToken.setToken(createToken(account.getId(), account.getUserName()));
        return userToken;
    }

    /**
     * 用户退出
     *
     * @param uid
     * @return
     */
    @Override
    public boolean logout(Long uid) {
        String key = RedisKeyConstant.USER_TOKEN_KEY + uid;
        return redisCache.deleteObject(key);
    }

    /**
     * 重置密码
     *
     * @param password 密码
     * @return
     */
    @Override
    public boolean resetPwd(String uid, String password) {
        Account account = accountMapper.selectById(uid);

        if (account == null) {
            throw new BusinessException(UserAccountEnum.USER_NOT_EXISTED);
        }

        if (!StringUtils.isBlank(password)) {
            String salt = generateSalt();
            String newPwd = DigestUtils.md5DigestAsHex(password.concat(salt).getBytes());
            account.setSalt(salt);
            account.setPassword(newPwd);

            account.setModifier(account.getUserAccount());
            account.setUpdateTime(LocalDateTime.now());
        }
        int i = accountMapper.updateById(account);
        return i > 0;
    }

    /**
     * 随即生成盐
     *
     * @return salt 盐
     */
    private String generateSalt() {
        return RandomStringUtils.randomAlphanumeric(20);
    }

    /**
     * 密码校验
     *
     * @param password 明文
     * @param salt     盐
     * @param hashPwd  密文
     * @return
     */
    private boolean checkPassword(String password, String salt, String hashPwd) {
        return hashPwd.equals(DigestUtils.md5DigestAsHex(password.concat(salt).getBytes()));
    }

    /**
     * 生成user token
     *
     * @param uid 用户账号ID
     * @return
     */
    private String createToken(Long uid, String userName) {
        String token = JwtUtil.createToken(uid, userName, userTokenConfig.getExpiredDays());
        String key = RedisKeyConstant.USER_TOKEN_KEY + uid;
        redisCache.setCacheObject(key, token, userTokenConfig.getExpiredDays(), TimeUnit.DAYS);
        return token;
    }
}
